﻿//Copyright 2011 - Jonathan Allen

using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows;
using System.Collections;
using System.Diagnostics.Contracts;

#if NUMERICS
using System.Numerics;
#endif

namespace Granite.Xaml.Converters
{
	/// <summary>
	/// Converts null to Collapsed.
	/// Converts 0 to Collapsed, other numbers to Visible.
	/// Throws on non-numeric types
	/// For WPF, the parameter is used to choose between Collapsed and Hidden. The default is Collapsed.
	/// </summary>
    [ValueConversion(typeof(Byte), typeof(Visibility))]
    [ValueConversion(typeof(SByte), typeof(Visibility))]
    [ValueConversion(typeof(Int16), typeof(Visibility))]
    [ValueConversion(typeof(UInt16), typeof(Visibility))]
    [ValueConversion(typeof(Int32), typeof(Visibility))]
    [ValueConversion(typeof(UInt32), typeof(Visibility))]
    [ValueConversion(typeof(Int64), typeof(Visibility))]
    [ValueConversion(typeof(UInt64), typeof(Visibility))]
    [ValueConversion(typeof(Decimal), typeof(Visibility))]
    [ValueConversion(typeof(Single), typeof(Visibility))]
    [ValueConversion(typeof(Double), typeof(Visibility))]
    [ValueConversion(typeof(Byte?), typeof(Visibility))]
    [ValueConversion(typeof(SByte?), typeof(Visibility))]
    [ValueConversion(typeof(Int16?), typeof(Visibility))]
    [ValueConversion(typeof(UInt16?), typeof(Visibility))]
    [ValueConversion(typeof(Int32?), typeof(Visibility))]
    [ValueConversion(typeof(UInt32?), typeof(Visibility))]
    [ValueConversion(typeof(Int64?), typeof(Visibility))]
    [ValueConversion(typeof(UInt64?), typeof(Visibility))]
    [ValueConversion(typeof(Decimal?), typeof(Visibility))]
    [ValueConversion(typeof(Single?), typeof(Visibility))]
    [ValueConversion(typeof(Double?), typeof(Visibility))]
    [ValueConversion(typeof(Byte), typeof(Visibility?))]
    [ValueConversion(typeof(SByte), typeof(Visibility?))]
    [ValueConversion(typeof(Int16), typeof(Visibility?))]
    [ValueConversion(typeof(UInt16), typeof(Visibility?))]
    [ValueConversion(typeof(Int32), typeof(Visibility?))]
    [ValueConversion(typeof(UInt32), typeof(Visibility?))]
    [ValueConversion(typeof(Int64), typeof(Visibility?))]
    [ValueConversion(typeof(UInt64), typeof(Visibility?))]
    [ValueConversion(typeof(Decimal), typeof(Visibility?))]
    [ValueConversion(typeof(Single), typeof(Visibility?))]
    [ValueConversion(typeof(Double), typeof(Visibility?))]
    [ValueConversion(typeof(Byte?), typeof(Visibility?))]
    [ValueConversion(typeof(SByte?), typeof(Visibility?))]
    [ValueConversion(typeof(Int16?), typeof(Visibility?))]
    [ValueConversion(typeof(UInt16?), typeof(Visibility?))]
    [ValueConversion(typeof(Int32?), typeof(Visibility?))]
    [ValueConversion(typeof(UInt32?), typeof(Visibility?))]
    [ValueConversion(typeof(Int64?), typeof(Visibility?))]
    [ValueConversion(typeof(UInt64?), typeof(Visibility?))]
    [ValueConversion(typeof(Decimal?), typeof(Visibility?))]
    [ValueConversion(typeof(Single?), typeof(Visibility?))]
    [ValueConversion(typeof(Double?), typeof(Visibility?))]
    [Pure]
    public partial class ZeroToVisibleConverter : OneWayMarkupValueConverter<ZeroToVisibleConverter>
	{
		/// <summary>
		/// 
		/// </summary>
		/// <param name="value"></param>
		/// <param name="targetType">Visibility</param>
		/// <param name="parameter"></param>
		/// <param name="culture"></param>
		/// <returns></returns>
		public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			CheckTargetType(targetType, typeof(Visibility), typeof(Visibility?));

			var newVisibility = Visibility.Collapsed;

#if !SILVERLIGHT
			if (parameter is Visibility)
				newVisibility = (Visibility)parameter;
			else
			{
				var stringParameter = parameter as String;
				if (stringParameter != null && stringParameter.ToUpperInvariant() == "HIDDEN")
					newVisibility = Visibility.Hidden;
			}
#endif

			bool returnValue;

			if (value == null)
				returnValue = false;
			//Common types
			else if (value is Int32)
				returnValue = (Int32)value == 0;
			else if (value is Decimal)
				returnValue = (Decimal)value == 0;
			else if (value is Single)
				returnValue = (Single)value == 0;
			else if (value is Double)
				returnValue = (Double)value == 0;


            else if (value is string)
                returnValue = ((string)value).Length == 0;
            else if (value is ICollection)
                returnValue = ((ICollection)value).Count == 0;
            else if (value is IEnumerable)
            {
                var enumerator = ((IEnumerable)value).GetEnumerator();

                if (enumerator.MoveNext()) //count >= 1
                    returnValue = false;
                else
                    returnValue = true;
            }

			//other numeric types
			else if (value is Byte)
				returnValue = (Byte)value == 0;
			else if (value is SByte)
				returnValue = (SByte)value == 0;
			else if (value is Int16)
				returnValue = (Int16)value == 0;
			else if (value is UInt16)
				returnValue = (UInt16)value == 0;
			else if (value is UInt32)
				returnValue = (UInt32)value == 0;
			else if (value is Int64)
				returnValue = (Int64)value == 0;
			else if (value is UInt64)
				returnValue = (UInt64)value == 0;
#if NUMERICS
			else if (value is BigInteger)
				returnValue = (BigInteger)value == 0;
#endif
			else
				throw new ArgumentException("value is not a number", "value");

			if (returnValue)
				return Visibility.Visible;
			else
				return newVisibility;

		}
	}

#if NUMERICS
    [ValueConversion(typeof(BigInteger), typeof(bool))]
    [ValueConversion(typeof(BigInteger?), typeof(bool))]
    [ValueConversion(typeof(BigInteger), typeof(bool?))]
    [ValueConversion(typeof(BigInteger?), typeof(bool?))]
    public partial class ZeroToVisibleConverter
    {

    }

#endif
}
